<!DOCTYPE html>
<html>
    <head>
        <title>VNC Performance Benchmark</title>
    </head>
    <body>

        Passes: <input id='passes' style='width:50' value=3>&nbsp;

        <input id='startButton' type='button' value='Start' style='width:100px'
            onclick="do_test();" disabled>&nbsp;

        <br><br>

        Results:<br>
        <textarea id="messages" style="font-size: 9;" cols=80 rows=15></textarea>

        <br><br>

        <div id="VNC_screen">
            <div id="VNC_status_bar" class="VNC_status_bar" style="margin-top: 0px;">
                <table border=0 width=100%><tr>
                    <td><div id="VNC_status">Loading</div></td>
                </tr></table>
            </div>
            <canvas id="VNC_canvas" width="640px" height="20px">
                Canvas not supported.
            </canvas>
        </div>

    </body>

    <!--
    <script type='text/javascript' 
        src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
    -->

    <script type="text/javascript">
        var INCLUDE_URI= "../include/";
        // TODO: Data file should override
        var VNC_frame_encoding = "binary";
    </script>
    <script src="../include/util.js"></script>
    <script src="../include/webutil.js"></script>

    <script>
        var fname = WebUtil.getQueryVar('data', null);
        if (fname) {
            msg("Loading " + fname);

            // Load supporting scripts
            Util.load_scripts(["base64.js", "websock.js", "des.js", "keysym.js",
                            "keysymdef.js", "keyboard.js", "input.js", "display.js",
                            "rfb.js", "playback.js", "inflator.js", fname]);
        } else {
            msg("Must specifiy data=FOO.js in query string.");
        }

        var start_time, VNC_frame_data, pass, passes, encIdx,
            encOrder = ['raw', 'rre', 'hextile', 'tightpng', 'copyrect'],
            encTot = {}, encMin = {}, encMax = {},
            passCur, passTot, passMin, passMax;

        function msg(str) {
            console.log(str);
            var cell = $D('messages');
            cell.innerHTML += str + "\n";
            cell.scrollTop = cell.scrollHeight;
        }
        function dbgmsg(str) {
            if (Util.get_logging() === 'debug') {
                msg(str);
            }
        }

        updateState = function (rfb, state, oldstate, mesg) {
            switch (state) {
                case 'failed':
                case 'fatal':
                    msg("noVNC sent '" + state +
                        "' state during pass " + pass +
                        ", iteration " + iteration +
                        " frame " + frame_idx);
                    test_state = 'failed';
                    break;
                case 'loaded':
                    $D('startButton').disabled = false;
                    break;
            }
            if (typeof mesg !== 'undefined') {
                $D('VNC_status').innerHTML = mesg;
            }
        }

        function do_test() {
            $D('startButton').value = "Running";
            $D('startButton').disabled = true;

            mode = 'perftest'; // full-speed
            passes = $D('passes').value;
            pass = 1;
            encIdx = 0;

            // Render each encoding once for each pass
            iterations = 1;

            // Initialize stats counters
            for (i = 0; i < encOrder.length; i++) {
                enc = encOrder[i];
                encTot[i] = 0;
                encMin[i] = 2<<23; // Something sufficiently large
                encMax[i] = 0;
            }
            passCur = 0;
            passTot = 0;
            passMin = 2<<23;
            passMax = 0;

            // Fire away
            next_encoding();
        }

        function next_encoding() {
            var encName;

            if (encIdx >= encOrder.length) {
                // Accumulate pass stats
                if (passCur < passMin) {
                    passMin = passCur;
                }
                if (passCur > passMax) {
                    passMax = passCur;
                }
                msg("Pass " + pass + " took " + passCur + " ms");

                passCur = 0;
                encIdx = 0;
                pass += 1;
                if (pass > passes) {
                    // We are finished
                    // Shut-off event interception
                    rfb.get_mouse().ungrab();
                    rfb.get_keyboard().ungrab();
                    $D('startButton').disabled = false;
                    $D('startButton').value = "Start";
                    finish_passes();
                    return; // We are finished, terminate
                }
            }

            encName = encOrder[encIdx];
            dbgmsg("Rendering pass " + pass + " encoding '" + encName + "'");

            VNC_frame_data = VNC_frame_data_multi[encName];
            iteration = 0;
            start_time = (new Date()).getTime();

            next_iteration();
        }

        // Finished rendering current encoding
        function finish() {
            var total_time, end_time = (new Date()).getTime();
            total_time = end_time - start_time;

            dbgmsg("Encoding " + encOrder[encIdx] + " took " + total_time + "ms");

            passCur += total_time;
            passTot += total_time;

            // Accumulate stats
            encTot[encIdx] += total_time;
            if (total_time < encMin[encIdx]) {
                encMin[encIdx] = total_time;
            }
            if (total_time > encMax[encIdx]) {
                encMax[encIdx] = total_time;
            }

            encIdx += 1;
            next_encoding();
        }

        function finish_passes() {
            var i, enc, avg, passAvg;
            msg("STATS (for " + passes + " passes)");
            // Encoding stats
            for (i = 0; i < encOrder.length; i++) {
                enc = encOrder[i];
                avg = (encTot[i] / passes).toFixed(1);
                msg("  " + enc + ": " + encTot[i] + " ms, " +
                    encMin[i] + "/" + avg + "/" + encMax[i] + 
                    " (min/avg/max)");

            }
            // Print pass stats
            passAvg = (passTot / passes).toFixed(1);
            msg("\n  All passes: " + passTot + " ms, " +
                passMin + "/" + passAvg + "/" + passMax +
                " (min/avg/max)");
        }

        window.onscriptsload = function() {
            var i, enc;
            dbgmsg("Frame lengths:");
            for (i = 0; i < encOrder.length; i++) {
                enc = encOrder[i];
                dbgmsg("  " + enc + ": " + VNC_frame_data_multi[enc].length);
            }
            $D('startButton').disabled = false;
        }
    </script>
</html>
